package com.tubang.common.util;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.SecretKeySpec;

import com.tubang.common.constant.Constants;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

@SuppressWarnings("restriction")
public class EncryptorUtil {
	
	private final static String encoding = "UTF-8";
	
	/**
	 * @author wsl 图邦
	 * @param content 需要加密的内容
	 * @return string 加密后32位字符串
	 * @Description: Aes256位加密
	 */
	public static String AesEncrypt(String content) {

		String password = Constants.ENCRYPT_KEY;
		byte[] encryptResult = encrypt(content, password);
		String encryptResultStr = bytes2Hex(encryptResult);
		return encryptResultStr;
	}

	/**
	 * @author wsl 图邦
	 * @param content 需要解密的内容
	 * @return string 解密后得到的字符串
	 * @Description: Aes256解密
	 */
	public static String AesDecrypt(String content) {
		String password = Constants.ENCRYPT_KEY;
		byte[] decryptFrom = hex2Bytes(content);
		byte[] decryptResult = decrypt(decryptFrom, password);
		return new String(decryptResult);
	}

	/**
	 * AES加密
	 * 
	 * @param content
	 * @param password
	 * @return
	 */
	public static String encryptAES(String content, String password) {
		byte[] encryptResult = encrypt(content, password);
		String encryptResultStr = bytes2Hex(encryptResult);
		// BASE64位加密
		encryptResultStr = ebotongEncrypto(encryptResultStr);
		return encryptResultStr;
	}

	/**
	 * AES解密
	 * 
	 * @param encryptResultStr
	 * @param password
	 * @return
	 */
	public static String decrypt(String encryptResultStr, String password) {
		// BASE64位解密
		String decrpt = ebotongDecrypto(encryptResultStr);
		byte[] decryptFrom = hex2Bytes(decrpt);
		byte[] decryptResult = decrypt(decryptFrom, password);
		return new String(decryptResult);
	}

	/**
	 * 加密字符串
	 */
	public static String ebotongEncrypto(String str) {
		BASE64Encoder base64encoder = new BASE64Encoder();
		String result = str;
		if (str != null && str.length() > 0) {
			try {
				byte[] encodeByte = str.getBytes(encoding);
				result = base64encoder.encode(encodeByte);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		// base64加密超过一定长度会自动换行 需要去除换行符
		return result.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");
	}

	/**
	 * 解密字符串
	 */
	public static String ebotongDecrypto(String str) {
		BASE64Decoder base64decoder = new BASE64Decoder();
		try {
			byte[] encodeByte = base64decoder.decodeBuffer(str);
			return new String(encodeByte);
		} catch (IOException e) {
			e.printStackTrace();
			return str;
		}
	}

	/**
	 * 加密
	 * 
	 * @param content 需要加密的内容
	 * @param password 加密密码
	 * @return
	 */
	private static byte[] encrypt(String content, String password) {
		try {
			KeyGenerator kgen = KeyGenerator.getInstance("AES");
			// 防止linux下 随机生成key
			SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
			secureRandom.setSeed(password.getBytes());
			kgen.init(128, secureRandom);
			// kgen.init(128, new SecureRandom(password.getBytes()));
			SecretKey secretKey = kgen.generateKey();
			byte[] enCodeFormat = secretKey.getEncoded();
			SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
			Cipher cipher = Cipher.getInstance("AES");// 创建密码器
			byte[] byteContent = content.getBytes("utf-8");
			cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
			byte[] result = cipher.doFinal(byteContent);
			return result; // 加密
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 解密
	 * @param content 待解密内容
	 * @param password 解密密钥
	 * @return
	 */
	private static byte[] decrypt(byte[] content, String password) {
		try {
			KeyGenerator kgen = KeyGenerator.getInstance("AES");
			// 防止linux下 随机生成key
			SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
			secureRandom.setSeed(password.getBytes());
			kgen.init(128, secureRandom);
			// kgen.init(128, new SecureRandom(password.getBytes()));
			SecretKey secretKey = kgen.generateKey();
			byte[] enCodeFormat = secretKey.getEncoded();
			SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
			Cipher cipher = Cipher.getInstance("AES");// 创建密码器
			cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
			byte[] result = cipher.doFinal(content);
			return result; // 加密
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 将二进制转换成16进制
	 * 
	 * @param buf
	 * @return
	 */
	public static String bytes2Hex(byte buf[]) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < buf.length; i++) {
			String hex = Integer.toHexString(buf[i] & 0xFF);
			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			sb.append(hex.toUpperCase());
		}
		return sb.toString();
	}

	public static String bytes2Hex2(byte[] inbuf) {
		int i;
		String byteStr;
		StringBuffer strBuf = new StringBuffer();
		for (i = 0; i < inbuf.length; i++) {
			byteStr = Integer.toHexString(inbuf[i] & 0x00ff);
			if (byteStr.length() != 2) {
				strBuf.append('0').append(byteStr);
			} else {
				strBuf.append(byteStr);
			}
		}
		return new String(strBuf);
	}

	/**
	 * 将16进制转换为二进制
	 * 
	 * @param hexStr
	 * @return
	 */
	public static byte[] hex2Bytes(String hexStr) {
		if (hexStr.length() < 1)
			return null;
		byte[] result = new byte[hexStr.length() / 2];
		for (int i = 0; i < hexStr.length() / 2; i++) {
			int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
			int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
			result[i] = (byte) (high * 16 + low);
		}
		return result;
	}

	/****
	 * 获取SHA1数据摘要
	 * 
	 * @param 输入数据
	 * @return 输出结果（16进制)
	 * @throws Exception
	 */
	public static String digest(byte[] oriByte) throws Exception {
		MessageDigest md = null;
		String strDes = null;
		md = MessageDigest.getInstance("SHA1");
		md.update(oriByte);
		strDes = bytes2Hex2(md.digest());
		return strDes;
	}

	/***
	 * 对数据进行签名
	 * 
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public static String signData(String data, PrivateKey privateKey) throws Exception {
		// PrivateKey key = getPrivateKey();
		Signature sig = Signature.getInstance("SHA1WithRSA");
		sig.initSign(privateKey);
		sig.update(data.getBytes("utf-8"));
		byte[] sigBytes = sig.sign();
		BASE64Encoder encoder = new BASE64Encoder();
		return encoder.encodeBuffer(sigBytes);
	}

	/****
	 * 对签名进行验证
	 * 
	 * @param data
	 * @param signValue
	 * @throws Exception
	 */
	public static void verifyData(String data, String signValue, PublicKey publicKey) throws Exception {
		try {
			Signature sig = Signature.getInstance("SHA1WithRSA");
			sig.initVerify(publicKey);
			sig.update(data.getBytes("utf-8"));
			BASE64Decoder decoder = new BASE64Decoder();
			byte[] signValueByte = decoder.decodeBuffer(signValue);
			if (!sig.verify(signValueByte)) {
				throw new Exception("E000013");
			}
			System.out.println("验签OK");
		} catch (Exception e) {
			throw new Exception("E000014", e);
		}
	}

	/****
	 * 获取cer文件中的公钥
	 * 
	 * @return
	 * @throws Exception
	 */
	public static PublicKey getPublicKey(String fileName) throws Exception {
		InputStream is = null;
		try {
			is = new FileInputStream(fileName);
			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
			return cert.getPublicKey();
		} catch (FileNotFoundException e) {
			throw new FileNotFoundException("没找到该文件.");
		} catch (CertificateException e) {
			throw new CertificateException("证书错误.");
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
				}
			}
		}
	}

	/****
	 * 获取秘钥文件中的私钥
	 * 
	 * @return
	 * @throws Exception
	 */
	public static PrivateKey getPrivateKey(String filename, String storePassword, String storeAlias) throws Exception {
		char[] storePwdArr;
		int i;
		BufferedInputStream bis = null;
		try {
			KeyStore ks = KeyStore.getInstance("JKS");
			FileInputStream fis = new FileInputStream(filename);
			bis = new BufferedInputStream(fis);
			storePwdArr = new char[storePassword.length()];// store password
			for (i = 0; i < storePassword.length(); i++) {
				storePwdArr[i] = storePassword.charAt(i);
			}
			ks.load(bis, storePwdArr);
			PrivateKey priv = (PrivateKey) ks.getKey(storeAlias, storePwdArr);
			return priv;
		} catch (KeyStoreException e) {
			throw new Exception("key store例外.");
		} catch (FileNotFoundException e) {
			throw new Exception("没找到该文件", e);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无法找到相应算法", e);
		} catch (CertificateException e) {
			throw new Exception("认证错误", e);
		} catch (IOException e) {
			throw new Exception("读取文件错误", e);
		} catch (UnrecoverableKeyException e) {
			throw new Exception("不可恢复key错误", e);
		} finally {
			if (bis != null) {
				try {
					bis.close();
				} catch (IOException e) {
				}
			}
		}
	}

	/****
	 * 3DES数据解密
	 * 
	 * @param sealTxt：密文数据
	 * @param keyStr：秘钥
	 * @return
	 * @throws Exception
	 */
	public static String DESDecrypt(String sealTxt, String keyStr) throws Exception {
		try {
			Cipher cipher = null;
			byte[] byteFina = null;
			SecretKey key = getKey(keyStr);
			try {
				cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
				cipher.init(Cipher.DECRYPT_MODE, key);
				BASE64Decoder decoder = new BASE64Decoder();
				byte[] sealByte = decoder.decodeBuffer(sealTxt);
				byteFina = cipher.doFinal(sealByte);
				return new String(byteFina, "utf-8");
			} catch (Exception e) {
				throw new Exception(e.getMessage(), e);
			} finally {
				cipher = null;
			}
		} catch (Exception ee) {
			throw new Exception(ee);
		}
	}

	/****
	 * 3DES加密
	 * 
	 * @param oriByte：原始数据
	 * @param keyStr：加密秘钥
	 * @return
	 * @throws Exception
	 */
	public static String DESEncrypt(byte[] oriByte, String keyStr) throws Exception {
		try {
			byte[] sealTxt = null;
			SecretKey key = getKey(keyStr);
			Cipher cipher = null;
			try {
				cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
				cipher.init(Cipher.ENCRYPT_MODE, key);
				sealTxt = cipher.doFinal(oriByte);
				BASE64Encoder encoder = new BASE64Encoder();
				String ret = encoder.encode(sealTxt);
				return ret;
			} catch (Exception e) {
				throw new Exception(e.getMessage(), e);
			} finally {
				cipher = null;
			}
		} catch (Exception ee) {
			throw new Exception(ee);
		}
	}

	/***
	 * @param key
	 * @return
	 * @throws Exception
	 */
	private static SecretKey getKey(String key) throws Exception {
		try {
			// 实例化DESede密钥
			DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("utf-8"));

			// 实例化密钥工厂
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");

			// 生成密钥
			SecretKey secretKey = keyFactory.generateSecret(dks);

			return secretKey;
		} catch (Exception e) {
			throw new Exception(e.getMessage(), e);
		}
	}

	public static void main(String[] args) {
		System.out.println(AesEncrypt("123456"));// 9D11417442E2E52A949580EC817A7C99
		String content = "111111";
		// 加密
		System.out.println("加密前：" + content);
		byte[] encryptResult = encrypt(content, "0hAbCcb^5etYXpRU9r835dSQtsA16!EhYCwFaX8N4hN&D8Z%fn");
		String encryptResultStr = bytes2Hex(encryptResult);
		System.out.println("加密后：" + encryptResultStr);
		// 解密
		byte[] decryptFrom = hex2Bytes(encryptResultStr);
		byte[] decryptResult = decrypt(decryptFrom, "0hAbCcb^5etYXpRU9r835dSQtsA16!EhYCwFaX8N4hN&D8Z%fn");
		System.out.println("解密后：" + new String(decryptResult));
	}

}